#include <benchmark/benchmark.h>
#include "sys/time.h"
#include "time.h"
#include "util.h"

using namespace std;

static void Bm_function_Nanosleep(benchmark::State &state)
{

    struct timespec ns_sleep1, ns_sleep2, ns_sleep3;
    ns_sleep1.tv_nsec = state.range(0);
    ns_sleep2.tv_nsec = state.range(1);
    ns_sleep3.tv_nsec = state.range(2);

    for (auto _ : state)
    {
        benchmark::DoNotOptimize(nanosleep(&ns_sleep1, &ns_sleep1));
        benchmark::DoNotOptimize(nanosleep(&ns_sleep2, &ns_sleep2));
        benchmark::DoNotOptimize(nanosleep(&ns_sleep3, &ns_sleep3));
    }
    state.SetItemsProcessed(state.iterations());
}

static void Bm_function_Clock_gettime(benchmark::State &state)
{

    struct timespec ns_sleep;

    for (auto _ : state)
    {

        benchmark::DoNotOptimize(clock_gettime(CLOCK_REALTIME, &ns_sleep));
        benchmark::DoNotOptimize(clock_gettime(CLOCK_MONOTONIC, &ns_sleep));
        benchmark::DoNotOptimize(clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ns_sleep));
        benchmark::DoNotOptimize(clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ns_sleep));
    }
    state.SetItemsProcessed(state.iterations());
}

static void Bm_function_Tzset(benchmark::State &state)
{
    time_t raw_time = time(NULL);
    struct tm *local_time = localtime(&raw_time);
    while (state.KeepRunning())
    {
        tzset();
    }
    local_time = localtime(&raw_time);

    state.SetItemsProcessed(state.iterations());
}

static void Bm_function_Gettimeofday(benchmark::State &state)
{
    struct  timeval now_time;
    for (auto _ : state)
    {
        benchmark::DoNotOptimize(gettimeofday(&now_time, nullptr));
    }
    state.SetItemsProcessed(state.iterations());
}

static void Bm_function_Localtime(benchmark::State &state){
    time_t raw_time;
    time(&raw_time);
    for (auto _ : state)
    {
        benchmark::DoNotOptimize(localtime(&raw_time));
    }
    state.SetItemsProcessed(state.iterations());
}

MUSL_BENCHMARK_WITH_ARG(Bm_function_Nanosleep, "NANO_SLEEP");
MUSL_BENCHMARK(Bm_function_Clock_gettime);
MUSL_BENCHMARK(Bm_function_Tzset);
MUSL_BENCHMARK(Bm_function_Gettimeofday);
MUSL_BENCHMARK(Bm_function_Localtime);